﻿using System;
namespace Layers.History
{
    public interface IStream
    {
        void Write(object value);
        object Read();
    }

    public interface IStream<E>
    {
        void Write(E value);
        E Read();
    }

    public abstract class DataNodeStream<E> : IStream<E>, IStream
    {
        protected DataNode _node;
        protected BitStream _bits;
        protected int _index;

        public DataNode Node { get { return _node; } }
        public BitStream BitStream { get { return _bits; } }

        public DataNodeStream(DataNode node, BitStream bits)
        {
            _node = node;
            _bits = bits;
        }

        public abstract void Write(E value);
        public abstract E Read();


        #region IStream Members

        void IStream.Write(object value)
        {
            this.Write((E)value);
        }

        object IStream.Read()
        {
            return (this as IStream<E>).Read();
        }

        #endregion
    }


    public class HuffmanNodeStream : DataNodeStream<int>
    {
        public HuffmanNode Node { get { return _node as HuffmanNode; } }

        public HuffmanNodeStream(DataNode node, BitStream bits) : base(node, bits) { }

        /// <summary>
        /// Compresses the code
        /// </summary>
        /// <param name="code"></param>
        public override void Write(int code)
        {
            _bits.Write(code, 3);
        }

        public override int Read()
        {
            return 1;
        }
    }

    public abstract class CodeNodeStream<E> : DataNodeStream<E>
    {
        protected E _tick;
        protected DataNodeStream<int> _intStream;

        public HuffmanNode Node { get { return _node as HuffmanNode; } }

        public CodeNodeStream(DataNodeStream<int> intstr)
            : base(intstr.Node, intstr.BitStream)
        {
            _intStream = intstr;
            _index = 0;
        }
    }

    public abstract class DiffNodeStream<E> : CodeNodeStream<E>
    {
        protected E _last;

        public DiffNodeStream(DataNodeStream<int> intstr)
            : base(intstr)
        {

        }

        public override void Write(E value)
        {
            if (0 == Node.Count)
            {
                Node.First = _last = value;
                Node.Count++;
                _index++;
            }
            else
            {
                int delta = ToCode(value);
                _intStream.Write(delta);
                _index++;
            }
        }

        public override E Read()
        {
            if (0 == _index)
                return (_last = (E)Node.First);
            int delta = _intStream.Read();
            _last = FromCode(delta);
            return _last;
        }

        public abstract int ToCode(E value);
        public abstract E FromCode(int value);
    }

    public class DiffNodeStream_Double : DiffNodeStream<double>
    {
        public DiffNodeStream_Double(DataNodeStream<int> intstr) : base(intstr) { }

        public override int ToCode(double value)
        {
            return (int)Math.Truncate((value - _last) / _tick);
        }
        public override double FromCode(int value)
        {
            return _last + value * _tick;
        }
    }

    public class DiffNodeStream_Int : DiffNodeStream<int>
    {
        public DiffNodeStream_Int(DataNodeStream<int> intstr) : base(intstr) { }

        public override int ToCode(int value)
        {
            return (value - _last) / _tick;
        }
        public override int FromCode(int value)
        {
            return _last + value * _tick;
        }
    }
}